﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using StreetlightGames.XnaEngine;
using Microsoft.Xna.Framework.Input;
using StreetlightGames.SpaceShooter.Enemies;
using Microsoft.Xna.Framework.Audio;

namespace StreetlightGames.SpaceShooter
{
    public class Player : DrawableGameComponent
    {
        private const double RESPAWN_TIME = 2;
        private const double EXPLOSION_TIME = 2;
        private const double CAPTURE_TIME = 3;
        private const double DOUBLE_UP_TIME = 6;

        private ModelObject _playerIcon;
        private double _elapsedStateTime;
        private KeyboardState _previousKeyboardState;
        private PlayerShip _playerShip1;
        private PlayerShip _playerShip2;
        private MotherShip _capturingShip;
        private Cue _captureCue;

        /// <summary>Gets or sets the Lives value</summary>
        public int Lives
        {
            get { return _lives; }
            set { _lives = value; }
        }
        private int _lives = 3;

        /// <summary>Gets or sets the State value</summary>
        public PlayerState State
        {
            get { return _state; }
            set
            {
                _state = value;
                _elapsedStateTime = 0;
            }
        }
        private PlayerState _state;

        /// <summary>Gets the IsDoubledUp value</summary>
        public bool IsDoubledUp
        {
            get { return _isDoubledUp; }
            internal set
            {
                _isDoubledUp = value;
                if (_isDoubledUp)
                {
                    _playerShip1.IsAlive = true;
                    _playerShip2.IsAlive = true;
                    _playerShip1.MinX = SpaceShooterGame.MinX;
                    _playerShip1.MaxX = SpaceShooterGame.MaxX - 60;
                    _playerShip2.MinX = SpaceShooterGame.MinX + 60;
                    _playerShip2.MaxX = SpaceShooterGame.MaxX;
                }
                else
                {
                    _playerShip1.IsAlive = true;
                    _playerShip2.IsAlive = false;
                    _playerShip1.MinX = SpaceShooterGame.MinX;
                    _playerShip1.MaxX = SpaceShooterGame.MaxX;
                }
            }
        }
        private bool _isDoubledUp;

        public Player(Game game)
            : base(game)
        {
            SpaceShooterGame spaceShooterGame = game as SpaceShooterGame;
            _playerShip1 = new PlayerShip(game, this);
            _playerShip1.Camera = spaceShooterGame.Camera;
            _playerShip1.IsAlive = true;
            Game.Components.Add(_playerShip1);

            _playerShip2 = new PlayerShip(game, this);
            _playerShip2.Camera = spaceShooterGame.Camera;
            _playerShip2.IsAlive = false;
            Game.Components.Add(_playerShip2);

            _playerIcon = new ModelObject(game, "Models\\GalagaShip");
            _playerIcon.Scale = 5;
            _playerIcon.Rotation = new Vector3(MathHelper.PiOver4, 0, 0);
            _playerIcon.Camera = spaceShooterGame.Camera;
            Game.Components.Add(_playerIcon);
        }

        public override void Update(GameTime gameTime)
        {
            _elapsedStateTime += gameTime.ElapsedGameTime.TotalSeconds;

            switch (State)
            {
                case PlayerState.Playing:
                    UpdatePlaying();
                    break;
                case PlayerState.Exploding:
                    UpdateExploding();
                    break;
                case PlayerState.Respawning:
                    UpdateRespawning();
                    break;
                case PlayerState.BeingCaptured:
                    UpdateBeingCaptured();
                    break;
                case PlayerState.DoublingUp:
                    UpdateDoublingUp();
                    break;
            }

            base.Update(gameTime);
        }

        internal void StartDoubleUp(Vector3 motherShipPosition)
        {
            State = PlayerState.DoublingUp;
            AudioController.Instance.PlayCue("GalagaRetrieveShip");
            _playerShip2.IsAlive = true;
            _playerShip2.Position = motherShipPosition + new Vector3(0, 0, -100);
        }

        private void UpdatePlaying()
        {
            KeyboardState keyboardState = Keyboard.GetState();

            SpaceShooterGame spaceShooterGame = Game as SpaceShooterGame;

            foreach (EnemyShip ship in spaceShooterGame.Wave.Ships)
            {
                if (CheckCollisions(ship, _playerShip1))
                {
                    break;
                }
            }
            if (IsDoubledUp)
            {
                foreach (EnemyShip ship in spaceShooterGame.Wave.Ships)
                {
                    if (CheckCollisions(ship, _playerShip2))
                    {
                        break;
                    }
                }
                if (!_playerShip1.IsAlive || !_playerShip2.IsAlive)
                {
                    IsDoubledUp = false;
                }
            }
            if (keyboardState.IsKeyDown(Keys.Left) && !keyboardState.IsKeyDown(Keys.Right))
            {
                _playerShip1.MoveLeft();
                if (_isDoubledUp)
                {
                    _playerShip2.MoveLeft();
                }
            }
            else if (keyboardState.IsKeyDown(Keys.Right) && !keyboardState.IsKeyDown(Keys.Left))
            {
                _playerShip1.MoveRight();
                if (_isDoubledUp)
                {
                    _playerShip2.MoveRight();
                }
            }
            else
            {
                _playerShip1.Stop();
                if (_isDoubledUp)
                {
                    _playerShip2.Stop();
                }
            }

            if (keyboardState.IsKeyDown(Keys.Space) && _previousKeyboardState.IsKeyUp(Keys.Space))
            {
                _playerShip1.FireMissile();
                if (_isDoubledUp)
                {
                    _playerShip2.FireMissile();
                }
            }

            _previousKeyboardState = keyboardState;
        }

        private void UpdateExploding()
        {
            if (_elapsedStateTime > EXPLOSION_TIME)
            {
                State = PlayerState.Respawning;
            }
        }

        private void UpdateRespawning()
        {
            if (_elapsedStateTime > RESPAWN_TIME)
            {
                State = PlayerState.Playing;
                _playerShip1.IsAlive = true;
            }
        }

        private void UpdateBeingCaptured()
        {
            _playerShip1.Rotation = new Vector3(0, (float)_elapsedStateTime / (float)CAPTURE_TIME * MathHelper.TwoPi * 3, 0);
            _playerShip1.Position = new Vector3(_playerShip1.Position.X, _playerShip1.Position.Y, _playerShip1.Position.Z - (float)_elapsedStateTime);
            _playerShip1.Stop();
            if (_elapsedStateTime > CAPTURE_TIME)
            {
                _capturingShip.Capture();
                State = PlayerState.Playing;
                _playerShip1.Position = new Vector3(0, 0, 0);
                _captureCue.Stop(AudioStopOptions.Immediate);
            }
        }
        
        private void UpdateDoublingUp()
        {
            Vector3 target = new Vector3(-30, 0, 0);
            Vector3 velocity = target - _playerShip1.Position;
            float delta = velocity.Length();
            if (delta < 10)
            {
                _playerShip1.Position = target;
                _playerShip1.Stop();
            }
            else
            {
                velocity.Normalize();
                velocity *= 100;
                _playerShip1.Velocity = velocity;
            }
            target = new Vector3(30, 0, 0);
            velocity = target - _playerShip2.Position;
            delta = velocity.Length();
            if (delta < 10)
            {
                _playerShip2.Position = target;
                _playerShip2.Stop();
            }
            else
            {
                velocity.Normalize();
                velocity *= 300;
                _playerShip2.Velocity = velocity;
            }
            if (_playerShip1.Velocity == Vector3.Zero && _playerShip2.Velocity == Vector3.Zero && _elapsedStateTime >= DOUBLE_UP_TIME)
            {
                IsDoubledUp = true;
                State = PlayerState.Playing;
            }
        }

        public override void Draw(GameTime gameTime)
        {
            SpaceShooterGame spaceShooterGame = Game as SpaceShooterGame;
            for (int i = 0; i < Lives - 1; i++)
            {
                _playerIcon.Position = Game.GraphicsDevice.Viewport.Unproject(
                                   new Vector3(
                                       Game.GraphicsDevice.Viewport.Width - 40 - 40 * i,
                                       40,
                                       0.999f),
                                   spaceShooterGame.Camera.ProjectionMatrix,
                                   spaceShooterGame.Camera.ViewMatrix,
                                   Matrix.Identity);
                _playerIcon.Draw(gameTime);
            }

            base.Draw(gameTime);
        }

        public void Start()
        {
            State = PlayerState.Playing;
            _playerShip1.Start();
            _playerShip2.Start();
        }
    
        internal void Restart()
        {
            Lives = 3;
            _playerShip1.IsAlive = true;
            IsDoubledUp = false;
            State = PlayerState.Playing;
            Start();
        }

        /// <summary>
        /// Checks to see if an enemy ship has collided with a player ship.  Returns true if a collision has
        /// occurred.  Returns false if no collision has occured.
        /// </summary>
        /// <param name="ship">Enemy ship</param>
        /// <param name="playerShip">Player ship</param>
        /// <returns>Boolean indicating whether a collision has occurred</returns>
        internal bool CheckCollisions(EnemyShip ship, PlayerShip playerShip)
        {
            MotherShip motherShip = ship as MotherShip;
            if (ship.IsAlive && VectorHelper.GetDistance(playerShip.Position, ship.Position) < 50f)
            {
                ship.Explode();
                playerShip.Explode();
                return true;
            }
            if (!IsDoubledUp && motherShip != null && motherShip.IsTractorBeamActive)
            {
                Vector3 delta = motherShip.Position - playerShip.Position;
                if (Math.Abs(delta.X) < 25)
                {
                    _capturingShip = motherShip;
                    motherShip.IsCapturingShip = true;
                    State = PlayerState.BeingCaptured;
                    _captureCue = AudioController.Instance.GetCue("GalagaCapture");
                    _captureCue.Play();
                }
            }
            foreach (Missile missile in ship.Missiles)
            {
                if (missile.IsAlive)
                {
                    if (VectorHelper.GetDistance(playerShip.Position, missile.Position) < 50)
                    {
                        missile.Explode();
                        playerShip.Explode();
                        return true;
                    }
                }
            }
            return false;
        }

        internal void AddFreeShip()
        {
            Lives++;
            AudioController.Instance.PlayCue("GalagaFreeShip");
        }
    }
}
